﻿using EasyOAuth.Core.Web;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace EasyOAuth.Base
{
    /// <summary>
    /// jwt授权扩展
    /// </summary>
    public static class JwtOAuthServiceCollectionExtensions
    {
        /// <summary>
        /// 添加jwt授权
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddJwtOAuth(this IServiceCollection services, IConfiguration configuration)
        {

            var securityKey = configuration.GetValue<string>("Jwt:SecurityKey") ?? string.Empty;
            var validAudience = configuration.GetValue<string>("Jwt:ValidAudience");
            var clockSkew = configuration.GetValue<double>("Jwt:ClockSkew");

            //添加jwt验证：
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateLifetime = true,//是否验证失效时间
                        ClockSkew = TimeSpan.FromSeconds(clockSkew),
                        ValidateIssuerSigningKey = true,//是否验证SecurityKey
                        ValidateAudience = true,//是否验证 Audience
                        ValidAudience = validAudience,//Audience
                        ValidateIssuer = true,//是否验证Issuer
                        ValidIssuer = validAudience,//Issuer
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey))//拿到SecurityKey
                    };

                    options.Events = new JwtBearerEvents()
                    {
                        OnChallenge = context =>
                        {
                            //终止默认的返回结果
                            context.HandleResponse();
                            string token = context.Request.Headers["Authorization"];
                            var result = JsonConvert.SerializeObject(new ApiResult { Code = 401, Msg = "登录过期" });
                            if (string.IsNullOrEmpty(token))
                            {
                                result = JsonConvert.SerializeObject(new ApiResult { Code = 401, Msg = "token不能为空" });
                                //验证失败返回401
                                context.Response.StatusCode = StatusCodes.Status200OK;
                                context.Response.WriteAsync(result);
                                return Task.FromResult(result);
                            }
                            try
                            {
                                JwtSecurityTokenHandler tokenheader = new();
                                ClaimsPrincipal claimsPrincipal = tokenheader.ValidateToken(token, options.TokenValidationParameters, out SecurityToken securityToken);
                            }
                            catch (SecurityTokenExpiredException)
                            {
                                result = JsonConvert.SerializeObject(new ApiResult { Code = 401, Msg = "登录已过期" });
                                //验证失败返回401
                                context.Response.StatusCode = StatusCodes.Status200OK;
                                context.Response.WriteAsync(result);
                                return Task.FromResult(result);
                            }
                            catch (Exception ex)
                            {
                                result = JsonConvert.SerializeObject(new ApiResult { Code = 402, Msg = "token令牌无效" });
                                //验证失败返回401
                                context.Response.StatusCode = StatusCodes.Status200OK;
                                context.Response.WriteAsync(result);
                                return Task.FromResult(result);
                            }

                            //验证失败返回401
                            context.Response.StatusCode = StatusCodes.Status200OK;
                            context.Response.WriteAsync(result);
                            return Task.FromResult(result);
                        }
                    };
                });
        }
    }
}
